<html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <title>Architecture Dependent Interface</title>
  <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">
  <meta name="keywords" content="Prex, embedded, real-time, operating system, RTOS, open source, free">
  <meta name="author" content="Kohsuke Ohtani">
  <link rel="stylesheet" type="text/css" href="../default.css" media="screen">
  <link rel="stylesheet" type="text/css" href="../print.css" media="print">
</head>
<body>
<div id="top">
</div>
<div id="middle">

<table id="content" cellpadding="0" cellspacing="0">
  <tbody>

    <tr>
      <td id="header" colspan="2" valign="top">
        <table width="100%" border="0" cellspacing="0" cellpadding="0">
        <tr>
          <td id="logo">
            <a href="http://prex.sourceforge.net/">
            <img alt="Prex logo" src="../img/logo.gif" border="0"
            style="width: 250px; height: 54px;"></a>
          </td>
          <td id="brief" align="right" valign="bottom">
            An Open Source, Royalty-free,<br>
	    Real-time Operating System
          </td>
        </tr>
        </table>
      </td>
    </tr>

    <tr>
      <td id="directory" style="vertical-align: top;">
      <a href="http://prex.sourceforge.net/">Prex Home</a> >
      <a href="index.html">Document Index</a> >
      Architecture Dependent Interface
    </tr>
    <tr><td class="pad" colspan="2" style="vertical-align: top;"></td></tr>

    <tr>
      <td id="doc" style="vertical-align: top;">
      <h1>Prex Architecture Dependent Interface</h1>

<p>
<i>Version 1.1.2, 2008/10/14</i>
</p>

<h3>Table of Contents</h3>
<ul>
  <li><a href="#intro">Introduction</a></li>
</ul>
<ul>
  <li><a href="#gen">General Information</a>
  <ul>
    <li><a href="#gen">Data Types</a></li>
    <li><a href="#gen">Boot Information</a></li>
  </ul>
  </li>
</ul>
<ul>
  <li><a href="#context">Context</a>
  <ul>
    <li><a href="#context">context_set</a></li>
    <li><a href="#context">context_switch</a></li>
    <li><a href="#context">context_save</a></li>
    <li><a href="#context">context_restore</a></li>
  </ul>
  </li>
</ul>
<ul>
  <li><a href="#int">Interrupt</a>
  <ul>
    <li><a href="#int">interrupt_enable</a></li>
    <li><a href="#int">interrupt_disable</a></li>
    <li><a href="#int">interrupt_save</a></li>
    <li><a href="#int">interrupt_restore</a></li>
    <li><a href="#int">interrupt_mask</a></li>
    <li><a href="#int">interrupt_unmask</a></li>
    <li><a href="#int">interrupt_setup</a></li>
  </ul>
  </li>
</ul>
<ul>
  <li><a href="#mmu">MMU</a>
  <ul>
    <li><a href="#mmu">mmu_init</a></li>
    <li><a href="#mmu">mmu_map</a></li>
    <li><a href="#mmu">mmu_newmap</a></li>
    <li><a href="#mmu">mmu_delmap</a></li>
    <li><a href="#mmu">mmu_switch</a></li>
    <li><a href="#mmu">mmu_extract</a></li>
  </ul>
  </li>
</ul>
<ul>
  <li><a href="#clock">Clock</a>
  <ul>
    <li><a href="#clock">clock_init</a></li>
  </ul>
  </li>
</ul>
<ul>
  <li><a href="#umem">User Memory</a>
  <ul>
    <li><a href="#umem">umem_copyin</a></li>
    <li><a href="#umem">umem_copyout</a></li>
    <li><a href="#umem">umem_strnlen</a></li>
  </ul>
  </li>
</ul>
<ul>
  <li><a href="#diag">Diagnostic</a>
  <ul>
    <li><a href="#diag">diag_init</a></li>
    <li><a href="#diag">diag_print</a></li>
  </ul>
  </li>
</ul>
<ul>
  <li><a href="#mach">Machine</a>
  <ul>
    <li><a href="#mach">machine_init</a></li>
    <li><a href="#mach">machine_idle</a></li>
    <li><a href="#mach">machine_reset</a></li>
    <li><a href="#mach">machine_setpower</a></li>
  </ul>
  </li>
</ul>
<ul>
  <li><a href="#loc">Memory Location</a>
  <ul>
    <li><a href="#loc">kern_area</a></li>
    <li><a href="#loc">user_area</a></li>
    <li><a href="#loc">phys_to_virt</a></li>
    <li><a href="#loc">virt_to_phys</a></li>
  </ul>
  </li>
</ul>
<br>
<br>

<h2 id="intro">Introduction</h2>

<p>
The interface for the architecture dependent layer is defined to abstract
a processor and minimum hardware in the Prex kernel.
If you want to port the Prex kernel to new architecture or new platform,
you have to modify the architecture dependent codes appropriately for
your target system. 
</p>
<p>
<img alt="Architecture Dependent Interface" src="img/arch.gif" border="1"
style="width: 404px; height: 287px;"><br>

<i><b>Figure 1. Architecture Dependent Interface</b></i>
</p>

<p>
Some functions in this interface are optional on the specific target.
For example, you don't have to implement the MMU support code if your
target system does not have a MMU.
</p>
<p>
It is important to minimize the number of functions in this interface.
This is because the porting work will increase if it has many functions.
So, the functions in this interface are
limited to minimum functions required to drive the Microkernel.
</p>

<h2 id="gen">General Information</h2>

<h3>Data Types</h3>
<p>
The following data types are defined by the architecture dependent layer.
</p>

<table border="1" width="70%" cellspacing="0">
<tbody>
<tr>
  <th>Data type</th>
  <th>Description</th>
</tr>
<tr>
  <td>context_t</td>
  <td>Define a processor register set for the thread context.</td>
</tr>
<tr>
  <td>pgd_t</td>
  <td>Define a page directory for the MMU.</td>
</tr>

</tbody>
</table>


<h3>Boot Information</h3>
<p>
The kernel and device drivers can use "boot information" which includes
the boot configuration and other system data.

Generally, almost all data in the boot information will be prepared by
the boot loader before loading a kernel.

In addition, the architecture dependent layer can write data
into the boot information within machine_init() routine.
</p>
<p>
 The format of the boot information:
</p>
<pre>
struct bootinfo
{
        struct vidinfo  video;
        struct physmem  ram[NMEMS];     /* physical ram table */
        int             nr_rams;        /* number of ram blocks */
        struct physmem  bootdisk;       /* boot disk in memory */
        int             nr_tasks;       /* number of boot tasks */
        struct module   kernel;         /* kernel image */
        struct module   driver;         /* driver image */
        struct module   tasks[1];       /* boot tasks image */
};
</pre>



<h2 id="context">Context</h2>
<p>
A context includes processor registers and additional per-thread
information. context_t represents the pointer to the context structure
of each architecture/platform. The kernel treats the pointer as a context
ID and it does not touch the internal data of the context structure.
</p>
<pre>
void context_set(context_t ctx, int type, vaddr_t val);
void context_switch(context_t prev, context_t next);
void context_save(context_t ctx);
void context_restore(context_t ctx);
</pre>

<dl>
<dt>context_set()</dt>
<dd>
Sets data <i>val</i> to the specific registers in <i>ctx</i>.
The <i>type</i> is one of the following register type.
<ul>
  <li>CTX_KSTACK - Set the kernel mode stack address.</li>
  <li>CTX_KENTRY - Set the kernel mode entry address.</li>
  <li>CTX_KARG   - Set the kernel mode argument.</li>
  <li>CTX_UENTRY - Set the user mode entry address.</li>
  <li>CTX_USTACK - Set the user mode stack address.</li>
  <li>CTX_UARG   - Set the user mode argument.</li>
</ul>
</dd>
</dl>

<dl>
<dt>context_switch()</dt>
<dd>
Switches the current context to new
context pointed by <i>next</i>.
</dd>
</dl>

<dl>
<dt>context_save()</dt>
<dd>
Saves the current user mode context to the thread local stack.
This is used to handle an exception.
</dd>
</dl>

<dl>
<dt>context_restore()</dt>
<dd>
Restores the saved user mode context to the
specified context.
</dd>
</dl>


<h2 id="int">Interrupt</h2>
<p>
The kernel abstracts whole interrupt related hardware. 
The architecture dependent interface provides only primitive routines
to handle the interrupt.
</p>

<pre>
void interrupt_enable(void);
void interrupt_disable(void);
void interrupt_save(int *sts);
void interrupt_restore(int sts);
void interrupt_mask(int vector);
void interrupt_unmask(int vector, int level);
void interrupt_setup(int vector, int mode);
</pre>

<dl>
<dt>interrupt_enable()</dt>
<dd>
Enables all interrupts.
</dd>
</dl>

<dl>
<dt>interrupt_disable()</dt>
<dd>
Disables all interrupts.
</dd>
</dl>

<dl>
<dt>interrupt_save()</dt>
<dd>
Saves current interrupt state to the address of <i>sts</i>.
</dd>
</dl>

<dl>
<dt>interrupt_restore()</dt>
<dd>
Restores the saved interrupt state from <i>sts</i>.
</dd>
</dl>

<dl>
<dt>interrupt_mask()</dt>
<dd>
Masks the interrupt for the specified interrupt <i>vector</i>.
</dd>
</dl>

<dl>
<dt>interrupt_unmask()</dt>
<dd>
Unmasks the interrupt for the specified
interrupt <i>vector</i>. The interrupt priority level is set to <i>level</i>.
</dd>
</dl>

<dl>
<dt>interrupt_setup()</dt>
<dd>
Programs the interrupt mode. <i>mode</i> is one of
the following value.
    <ul>
      <li>IMODE_EDGE - Edge trigger</li>
      <li>IMODE_LEVEL - Level trigger</li>
    </ul>
</dd>
</dl>

<h2 id="mmu">MMU</h2>
<p>
The architecture dependent code must provide the functions for
Memory Management Unit (MMU). Even if the system does not support MMU,
mmu_init() and mmu_switch() must be defined as NULL macro.
</p>

<pre>
void  mmu_init(struct mmumap *mmumap_table);
int   mmu_map(pgd_t pgd, void *phys, void *virt, size_t size, int type);
pgd_t mmu_newmap(void);
void  mmu_delmap(pgd_t pgd);
void  mmu_switch(pgd_t pgd);
void *mmu_extract(pgd_t pgd, void *virt, size_t size);
</pre>

<dl>
<dt>mmu_init()</dt>
<dd>
Initializes the memory management unit.
</dd>
</dl>

<dl>
<dt>mmu_map()</dt>
<dd>
Maps physical memory range <i>phys</i> into the
virtual address <i>virt</i>. <i>type</i> is one of the following mapping type.
<ul>
  <li>PG_UNMAP - Remove mapping</li>
  <li>PG_READ - Read only mapping</li>
  <li>PG_WRITE - Read/write are allowed</li>
  <li>PG_SYSTEM - System memory</li>
  <li>PG_IOMEM - I/O memory</li>
</ul>
It returns 0 on success, or -1 on failure.
</dd>
</dl>

<dl>
<dt>mmu_newmap()</dt>
<dd>
Creates a new map. It returns new page directory on success,
or NULL on failure. This routine will be called when new task is created.
</dd>
</dl>

<dl>
<dt>mmu_delmap()</dt>
<dd>
Deletes all page mapping in the page directory <i>pgd</i>.
</dd>
</dl>

<dl>
<dt>mmu_switch()</dt>
<dd>
Switchs to new page directory specified in <i>pgd</i>. This is called when
the thread is switched.
</dd>
</dl>

<dl>
<dt>mmu_extract()</dt>
<dd>
Returns the physical address for the specified virtual
address. It returns NULL if at least one page is not mapped.
</dd>
</dl>

<h2 id="clock">Clock</h2>
The Prex kernel requires a clock timer hardware for all systems.
<pre>
void clock_init(void);
</pre>

<dl>
<dt>clock_init()</dt>
<dd>
Initializes the clock timer device.
</dd>
</dl>

<h2 id="umem">User Memory</h2>
<p>
Since accessing to the user memory may cause a page fault, 
the manipulation of the user buffer is handled by each architecture codes.
The following functions should detect the page fault and return an error
if it can.
</p>

<pre>
int umem_copyin(void *uaddr, void *kaddr, size_t len);
int umem_copyout(void *kaddr, void *uaddr, size_t len);
int umem_strnlen(const char *uaddr, size_t maxlen, size_t *len);
</pre>

<dl>
<dt>umem_copyin</dt>
<dd>
Copies the data to the kernel area from the user buffer.
It returns 0 on success, or EFAULT on page fault.
</dd>
</dl>

<dl>
<dt>umem_copyout</dt>
<dd>
Copies the data from the kernel buffer to the user area.
It returns 0 on success, or EFAULT on page fault.
</dd>
</dl>

<dl>
<dt>umem_strnlen</dt>
<dd>
Gets the string length specified in <i>uaddr</i>.
It returns 0 on success, or EFAULT on page fault.
</dd>
</dl>


<h2 id="diag">Diagnostic</h2>

<pre>
void diag_init(void);
void diag_print(char *buf);
</pre>

<dl>
<dt>diag_init()</dt>
<dd>
Initialize diagnostic port.
</dd>
</dl>

<dl>
<dt>diag_print()</dt>
<dd>
Puts the message specified by <i>buf</i> to the output device.
</dd>
</dl>


<h2 id="mach">Machine</h2>

<pre>
void machine_init(void);
void machine_idle(void);
void machine_reset(void);
void machine_setpower(int state);
</pre>

<dl>
<dt>machine_init()</dt>
<dd>
Initialize basic h/w.
</dd>
</dl>

<dl>
<dt>machine_idle()</dt>
<dd>
Sets the system to the low power mode until any interrupt occurs.
</dd>
</dl>

<dl>
<dt>machine_reset()</dt>
<dd>
Resets the system.
</dd>
</dl>

<dl>
<dt>machine_setpower()</dt>
<dd>
Set the system power state.
    <ul>
      <li>POW_SUSPEND - Suspend</li>
      <li>POW_OFF - Power off</li>
    </ul>
</dd>
</dl>


<h2 id="loc">Memory Location</h2>
<pre>
int   kern_area(void *addr);
int   user_area(void *addr);
void *phys_to_virt(void *p_addr);
void *virt_to_phys(void *v_addr);
</pre>

<dl>
<dt>kern_area()</dt>
<dd>
Returns true if specified <i>addr</i> is in the kernel area.
</dd>
</dl>

<dl>
<dt>user_area()</dt>
<dd>
Returns true if specified <i>addr</i> is in the user area.
</dd>
</dl>

<dl>
<dt>phys_to_virt()</dt>
<dd>
Returns the virtual address mapped to the
physical address in <i>p_addr</i>.
</dd>
</dl>

<dl>
<dt>virt_to_phys()</dt>
<dd>
Returns the physical address mapped to the
virtual address in <i>v_addr</i>.
</dd>
</dl>

      </td>
    </tr>
    <tr>
      <td id="footer" colspan="2" style="vertical-align: top;">
        <a href="http://sourceforge.net">
        <img src="http://sourceforge.net/sflogo.php?group_id=132028&amp;type=1"
        alt="SourceForge.net Logo" border="0" height="31" width="88"></a><br>
        Copyright&copy; 2005-2007 Kohsuke Ohtani
      </td>
    </tr>

  </tbody>
</table>

</div>
<div id="bottom"></div>

</body>
</html>
